<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><title>Running long JavaScript processes in a web browser (optimized version)</title>

  
    
    <style>

body {
  padding: 0 1em;
  overflow: hidden;
}

div.progressbar {
  position:relative;
  width:300px; height:20px;
  border:1px solid black;
  margin: 2em 0 0.5em;
  overflow:hidden;
}

div.progressbar div {
  background:#316AC5;
  width:0; height:100%;
  color: #fff;
  text-indent: 10px;
}

div.out {
  background: #def;
  border: 1px solid #789;
  margin-left: -2px;
  font: 10px Arial;
  height: 32px;
  width: 100%;
  overflow: auto;
}

    </style></head><body>
    <p>Sorting, please wait...</p>
    <div class="progressbar"><div id="progress1"></div></div>
    <div id="out1" class="out">&nbsp;</div>
    
    <div class="progressbar"><div id="progress2"></div></div>
    <div id="out2" class="out">&nbsp;</div>

    <div class="progressbar"><div id="progress3"></div></div>
    <div id="out3" class="out">&nbsp;</div>
    
    <script>

(function () {

    var globalStart;
    var currentContext = null;
    
    var contexts = [
      // context 0
      {
        i: 0,
        length: 2000,
        data: [],
        timeSlice: 50,
        next: null,
        el: null,
        elId: 'progress1',
        out: null,
        outId: 'out1'

      // context 1
      },{
        i: 0,
        length: 2000,
        data: [],
        timeSlice: 50,
        next: null,
        el: null,
        elId: 'progress2',
        out: null,
        outId: 'out2'

      // context 2
      },{
        i: 0,
        length: 2000,
        data: [],
        timeSlice: 50,
        next: null,
        el: null,
        elId: 'progress3',
        out: null,
        outId: 'out3'
      }
    ];

    // Setup all contexts
    for (var c=0, cc, cl=contexts.length; cc=contexts[c]; c++) {
      var data = cc.data;
      
      cc.el = document.getElementById(cc.elId);
      cc.out = document.getElementById(cc.outId);
      
      // link the contexts in a circular reference
      cc.next = contexts[(c+1)%cl];
      cc.last = contexts[(cl+c-1)%cl];
      
      for (var i = 0, l = cc.length; i < l; i++) {
          //data[i] = Math.floor(Math.random() * l);
          data[i] = l-i;
      }
    }

    function sort () {
        var j, value, start;
        
        // load context
        var c = currentContext;
        var length = c.length;
        var i = c.i;
        var data = c.data;
  
        start = new Date().getTime();
        for (; i < length; i++) {
  
            for (j = length; j > i; j--) {
                if (data[j] < data[j - 1]) {
                    value = data[j];
                    data[j] = data[j - 1];
                    data[j - 1] = value;
                }
            }
  
            if (new Date().getTime() - start > c.timeSlice) {
                i++;
                //currentContext = c.next; // switch context
                setTimeout(sort, 0); // queue next context
                break; // interruption
            }
        }
  
        // Evaluate the progress
        c.el.style.width = (100 * i / length) + "%";
        if (i >= length) {
            c.el.innerHTML = "Total time: " + ((new Date().getTime() - globalStart) / 1000) + " seconds";
            c.out.innerHTML = data+'';
            
            // remove the completed context from the circular queue
            var next = c.next;
            if (next.i < next.length) {
              next.last = c.last;
              c.last.next = next; 
              currentContext = next; // switch context
              setTimeout(sort, 0); // queue next context
            }
        }
        c.i = i; // sync context
    };


    globalStart = new Date().getTime();
    currentContext = contexts[0];
    sort();

})();

    </script>
  
</body></html>